#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Predesys Server - Core - Data
@version: 0.2.5
@license: GPL 3.0 (see "license" file)
@author: Jose A. Jimenez
@contact: jajimc@gmail.com"""

import sys
sys.dont_write_bytecode = True
import os
import os.path
DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.path.join(DIR, "../errorlog"))
import errorlog
import exceptions
import coreexceptions
import sqlalchemy
import sqlalchemy.engine.base
import configuration
    
def get_supported_db_systems():
    """Gets a list of supported data base systems.
    @return: List of DB systems
    @rtype: C{str}"""
    return ["mysql"]

def open_connection():
    """Opens a DB connection.
    @return: DB connection object
    @rtype: C{sqlalchemy.engine.base.Connection}"""
    connection = None
    config = configuration.load_configuration()

    dbType = config.get_db_type()
    if dbType == None: raise coreexceptions.DataBaseException("Data base settings not set") 
    
    dbHost = config.get_db_host()
    if dbHost == None: raise coreexceptions.DataBaseException("Data base settings not set") 
    
    dbPort = config.get_db_port()
    
    dbName = config.get_db_name()
    if dbName == None: raise coreexceptions.DataBaseException("Data base settings not set") 
    
    dbUserName = config.get_db_user_name()
    if dbUserName == None: raise coreexceptions.DataBaseException("Data base settings not set") 
    
    dbUserPassword = config.get_db_user_password()
    if dbUserPassword == None: raise coreexceptions.DataBaseException("Data base settings not set") 
    
    if dbType == "mysql":
        if dbPort == None: dbConnectionString = "mysql+mysqldb://%s:%s@%s/%s" % (dbUserName, dbUserPassword, dbHost, dbName)
        else: dbConnectionString = "mysql+mysqldb%s://%s:%s@%s:%d/%s" % (dbUserName, dbUserPassword, dbHost, dbPort, dbName)     
        
        try: 
            connection = (sqlalchemy.create_engine(dbConnectionString, encoding="utf8")).connect()
        except Exception as exc:
            errorlog.log_exception(exc.args[0], "predesys-server.core.data.open_connection")
            raise coreexceptions.DataBaseException("Data base connection error")
    else:
        errorlog.log_exception(Exception("Database type not supported"), "predesys-server.core.data.open_connection")
        raise coreexceptions.DataBaseException("Data base type not supported")
        
    return connection
    
def execute(connection, statement):
    """Executes a SQL statement.
    @param connection: DB connection
    @type connection: C{sqlalchemy.engine.base.Connection}
    @param statement: SQL statement
    @type statement: C{str}"""
    if connection == None or type(connection) != sqlalchemy.engine.base.Connection: raise coreexceptions.ValueNotValidException("'connection' must be a not null Connection object.")
    if statement == None or (type(statement) != str and type(statement) != unicode) or statement == "": raise coreexceptions.ValueNotValidException("'statement' must be a valid SQL statement.")
    filter_sql(statement)
    
    try:
        return connection.execute(statement)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.data.execute")
        raise coreexceptions.DataBaseException("Data base error")
        
def filter_sql(sentence):
    """Filters a SQL sentence in order to prevent the modification of the data base structure.
    @param sentence: SQL sentence
    @type sentence: C{str}
    @todo: Implement the function"""
    # This function must prevent database structure modification and throw exceptions if needed
    pass

def close_connection(connection):
    """Closes an opened DB connection.
    @param connection: DB connection
    @type connection: C{sqlalchemy.engine.base.Connection}"""
    if connection == None or type(connection) != sqlalchemy.engine.base.Connection: raise coreexceptions.ValueNotValidException("'connection' must be a not null Connection object.")
    
    try:
        connection.close()
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.data.close_connection")
        raise coreexceptions.DataBaseException("Data base closing error")
